/*
 * Msg.cpp
 *
 *  Created on: 2014. 7. 21.
 *      Author: mega
 */

#include "Static.h"
#include "Ack.h"
#include "Enum.h"
#include "ChannelServer.h"
#include "Guild.h"
#include "Function.h"
#include "GuildRank.h"
#include "NResource/Static.h"

#include <Dispatcher/Session.h>
#include <Network/Packet.h>

namespace GuildServer {

void
Msg::OnReloadResourceSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ReloadResourceSyn syn;
	pPacket->Read(syn);

	bool ret = NResource::Static::Instance().LoadResource();
	LOG(DEV, __FUNCTION__, " : Reload Resource ret : ", ret);
}


void
Msg::OnUpdateGuildLoginTimeSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	UpdateGuildLoginTimeSyn syn;
	pPacket->Read(syn);

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );

	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		pGuild = Static::Instance().LoadGuild(syn.guild_seq);
	}

	if (NULL == pGuild)
		return;

	std::shared_ptr<Member> pMember = pGuild->GetMember(syn.user_seq);
	if (NULL == pMember)
	{
		LOG(ERR, __FUNCTION__, " : Not exists member. guild_seq : ", syn.guild_seq, " user_seq : ", syn.user_seq);
		return;
	}

	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " : pBalance is NULL");
		return;
	}

	// 길드원 접속 점수
	int connectPoint = 0;
	{
		NResource::ResourceGuildBanalce::Flyweight * pFly = pBalance->GetFly(GUILD_CONNECT_POINT);
		if (NULL == pFly)
		{
			LOG(ERR, __FUNCTION__, " : pFly(GUILD_CONNECT_POINT) is NULL");
			return;
		}

		connectPoint = pFly->_VALUE;
	}

	int dailyMaxScore = pBalance->GetMemberDailyMaxScore();
	if (0 >= dailyMaxScore)
	{
		LOG(ERR, __FUNCTION__, " : member daily max score get fail.");
		return;
	}

	time_t checkStartTime = GetAttendanceCheckTime();
	time_t checkEndTime = checkStartTime + (60 * 60 * 24);

	if (true == Static::Instance().GetTest())
		checkEndTime = checkStartTime + (60 * 20);

	LOG(DEV, __FUNCTION__, " : Attendance Check StartTime : ", checkStartTime, ", EndTime : ", checkEndTime, ", LoginTime : ", pMember->GetData()._loginTime);

	// 이미 출석 점수를 받은 경우
	if (checkStartTime < pMember->GetData()._loginTime
			&& pMember->GetData()._loginTime < checkEndTime)
		return;

	pMember->GetData()._loginTime = time(NULL);

	// 로그인 시간 갱신
	pMember->FlushLoginTime();

	// 멤버 포인트 반영
	pMember->ChangeMemberScore(connectPoint, dailyMaxScore);
	pMember->SetMemberFlushDB(true);

	// 일일 최대 포인트를 획득한 경우 길드 포인트에 반영 하지 않는다.
	if (dailyMaxScore <= pMember->GetData()._dailyScore)
		return;

	// 길드 포인트 반영
	pGuild->ChangeScore(connectPoint);
	pGuild->SetFlushDB(true);
	pGuild->SetTimer();
}


void
Msg::OnLoginGuildMemberSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	LoginGuildMemberSyn syn;
	pPacket->Read(syn);

	MyGuildInfoAck ack;
	ack.user_seq = syn.user_seq;


	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );

	//--------------------------------------------------------------------------------------------
	// 10. guild instance 존재 여부 파악
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( syn.guild_seq );
	if ( NULL == pGuild )
	{ // 길드 data를 DB에서 로딩
		pGuild = Static::Instance().LoadGuild( syn.guild_seq );
	}

	if ( NULL == pGuild ) // 길드 정보 loading에 실패할 수 있다.
	{
		LOG(ERR, __FUNCTION__, "> ACK_GUILD_INFO_FAILED> MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );

		//----------------------------------------------------------------------------------------------
		// commented by spencer(2014.08.26)
		//
		// 길드원A를 강퇴하고 길드를 해체할 경우, 길드원A가 재접속해서 길드 로그인을 하려고 할 때, 해당 길드 정보 로딩에 실패를 하게 된다.
		// 해당 길드는 이미 해체되었으므로 select 시에 결과 recordset이 없다.(정상인 길드만으로 where 조건이 되어 있다.)
		// 따라서 탈퇴되었는지 등에 대한 상세 정보를 확인할 수 없다.
		// 실제로 길드 정보가 없는 것인지? 아니면 해체를 해서 없는 것인지 구분을 명확히 해줘야 한다.
		//----------------------------------------------------------------------------------------------
		int eRes = ACK_OK;
		int32_t iStatus = 0;
		uint32_t guild_seq2 = 0;
		std::string stGuildName;

		{
			Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER), "call sp_select_guild_member_status(", syn.user_seq, ")");
			if (0 != res.GetSQLError())
			{
				LOG(ERR, __FUNCTION__, " : Fail call sp_select_guild_member_status");
				eRes = ACK_DB_ERROR;
			}
			else if (0 == res.GetRowCount())
			{
				LOG(ERR, __FUNCTION__, " : have no member data.");
				eRes = ACK_DB_ERROR;
			}
			else
			{
				int idx = 1;
				for (Database::ResultSet::iterator iter = res.begin(); iter != res.end(); iter++)
				{
					guild_seq2 = iter->getInt(idx++); // result
					iStatus = iter->getInt(idx++);
					stGuildName = iter->getString(idx++).c_str();
				}
			}
		}

		MyGuildInfoAck ack;
		ack.user_seq = syn.user_seq;
		ack.result = ACK_GUILD_INFO_FAILED;

		if ( ACK_OK == eRes && 1 < iStatus ) // 1: 가입중, 2:탈퇴중, 3:탈퇴, 4:추방중, 5:추방
		{
			ack.result = ACK_GUILD_MEMBER_LOGIN_WAS_KICKEDOUT;
			ack.stInfo.seq = guild_seq2;
			ack.stInfo.name = stGuildName.c_str();

			LOG(DEV, "10. Member kicked out!!!> user_seq: ", syn.user_seq, ", guild_seq: ", syn.guild_seq, ", status: ", iStatus, ", guild: ", ack.stInfo.name.c_str() );
		}


		pChannel->SendMsg(ack);
		return;
	}


	GuildServer::Guild::GuildInfo kGuildInfo = pGuild->GetData();

	//--------------------------------------------------------------------------------------------
	// 20. 내가 길드에 가입되어 있는지 확인
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Member> pMember = pGuild->GetMember( syn.user_seq );
	if ( NULL == pMember )
	{ // 내가 가입되어 있지 않다. 즉 내가 추방되었다. front-end에 이를 전달해서 최종적으로 client에 해당 메시지를 출력한다. "길드에서 추방되었습니다."
		// DB에 사유를 물어볼까?
		MyGuildInfoAck ack;
		ack.user_seq = syn.user_seq;
		ack.result = ACK_GUILD_MEMBER_LOGIN_WAS_KICKEDOUT;
		ack.stInfo.seq = pGuild->GetSeq();
		ack.stInfo.name = kGuildInfo._name;

		pChannel->SendMsg(ack);

		LOG(DEV, "20. Member kicked out!!!> user_seq: ", syn.user_seq, ", guild_seq: ", syn.guild_seq );

		return;
	}

	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " pBalance is NULL.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);

		return;
	}

	int guildMaxUser =  pBalance->GetGuildMaxUser(kGuildInfo._grade);
	if (0 >= guildMaxUser)
	{
		LOG(ERR, __FUNCTION__, " Guild max user get fail. grade : ", kGuildInfo._grade);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);

		return;
	}

	int guildNextPoint = pBalance->GetNextGradeGuildScore(kGuildInfo._grade);
	if (0 >= guildNextPoint)
	{
		LOG(ERR, __FUNCTION__, " Guild next point get fail.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);

		return;
	}


	//--------------------------------------------------------------------------------------------
	// 30. 멤버 정보 update
	//--------------------------------------------------------------------------------------------
	//int iOldServer = pMember->GetServer();
	pMember->SetServer( syn.server_id );
	GuildServer::Member::MemberInfo kMyInfo = pMember->GetData();
	if ( syn.level != kMyInfo._level || syn.nickname != kMyInfo._nickname /*|| syn.socialid != kInfo._socialID*/ )
	{ // DB 업데이트 수행

		pMember->SetNickname( syn.nickname.c_str(), syn.level );
		LOG(DEV, __FUNCTION__, "> nickname: ", pMember->GetData()._nickname.c_str(), ", level: ", pMember->GetData()._level);
	}


	std::shared_ptr<Member> pMaster = pGuild->GetMember( kGuildInfo._masterSeq );
	if ( NULL == pMaster )
	{
		LOG(ERR, __FUNCTION__, " Master is null.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);

		return;
	}


	ack.result = ACK_OK;
	ack.stInfo.seq = pGuild->GetSeq();
	ack.stInfo.name = kGuildInfo._name;
	ack.stInfo.master_seq = kGuildInfo._masterSeq;
	ack.stInfo.master_socialid = pMaster->GetData()._socialID;
	ack.stInfo.master_nickname = pMaster->GetData()._nickname;
	ack.stInfo.master_profile_url = pMaster->GetData()._profileURL;
	ack.stInfo.master_level = pMaster->GetData()._level;
	ack.stInfo.level = kGuildInfo._grade;
	ack.stInfo.member_count = pGuild->GetMemberTree().size();
	ack.stInfo.max_member_count = guildMaxUser;
	ack.stInfo.buff_type = kGuildInfo._buffType;
	ack.stInfo.buff_level = kGuildInfo._buffLevel;
	ack.stInfo.buff_value = kGuildInfo._buffValue;
	ack.stInfo.notice_flag = GetGuildExposureStatus(kGuildInfo._exposure, kGuildInfo._password);
	ack.stInfo.notice_text = kGuildInfo._intro;
	ack.stInfo.password = kGuildInfo._password;
	ack.stInfo.point = kGuildInfo._score;
	ack.stInfo.max_point = guildNextPoint; // resource data로 교체
	ack.stInfo.prev_point = kGuildInfo._prevScore; // snap shot 이 주기적으로 저장되어야 한다.
	ack.stInfo.rank = pGuild->GetRank();
	ack.stInfo.prev_rank = kGuildInfo._prevRank;

	pChannel->SendMsg(ack);


	//LOG(DEV, "Member logined> ", pMember->GetSeq(), ", ", pMember->GetData()._nickname, ", ", pMember->GetData()._socialID, ", server: ", pMember->GetServer(), "(", iOldServer, ")" );
}


void
Msg::OnLogoutGuildMemberSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	//ChannelServer * pChannel = (ChannelServer *)pSession;

	LogoutGuildMemberSyn syn;
	pPacket->Read(syn);


	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );


	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( syn.guild_seq );
	if ( NULL == pGuild )
		return;

	std::shared_ptr<Member> pMember = pGuild->GetMember( syn.user_seq );
	if ( NULL == pMember )
		return;

	//int iOldServer = pMember->GetServer();
	pMember->SetServer( 0 );

	// 멤버 Point 정보 DB 갱신
	pMember->SetMemberFlushDB(true);
	pMember->FlushMemberPoint();

	// 접속된 길드원이 없으면 Point 정보 DB 갱신
	if (0 >= pGuild->GetConnectMemberCount())
	{
		pGuild->SetFlushDB(true);
		pGuild->FlushGuildPoint();
	}

	//LOG(DEV, "Member logouted> ", pMember->GetSeq(), ", ", pMember->GetData()._nickname, ", ", pMember->GetData()._socialID, ", server_id: ", pMember->GetServer(), "(", iOldServer, ")" );
}


void
Msg::OnGuildInfoSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildInfoSyn syn;
	pPacket->Read(syn);


	GuildInfoAck ack;
	ack.user_seq = syn.user_seq;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );

	//--------------------------------------------------------------------------------------------
	// 10. guild instance 존재 여부 파악
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( syn.guild_seq );
	if ( NULL == pGuild )
	{ // 길드 data를 DB에서 로딩
		pGuild = Static::Instance().LoadGuild( syn.guild_seq );
	}

	if ( NULL == pGuild )
	{
		pChannel->SendFail(ack, ACK_GUILD_INFO_FAILED);
		return;
	}

	GuildServer::Guild::GuildInfo kGuildInfo = pGuild->GetData();
	std::shared_ptr<Member> pMaster = pGuild->GetMember( kGuildInfo._masterSeq );
	if ( NULL == pMaster )
	{
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " pBalance is NULL.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	int guildMaxUser =  pBalance->GetGuildMaxUser(kGuildInfo._grade);
	if (0 >= guildMaxUser)
	{
		LOG(ERR, __FUNCTION__, " Guild max user get fail. grade : ", kGuildInfo._grade);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	int guildNextPoint = pBalance->GetNextGradeGuildScore(kGuildInfo._grade);
	if (0 >= guildNextPoint)
	{
		LOG(ERR, __FUNCTION__, " Guild next point get fail.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}


	ack.result = ACK_OK;
	ack.stInfo.seq = pGuild->GetSeq();
	ack.stInfo.name = kGuildInfo._name;
	ack.stInfo.master_seq = kGuildInfo._masterSeq;
	ack.stInfo.master_socialid = pMaster->GetData()._socialID;
	ack.stInfo.master_nickname = pMaster->GetData()._nickname;
	ack.stInfo.master_profile_url = pMaster->GetData()._profileURL;
	ack.stInfo.master_level = pMaster->GetData()._level;
	ack.stInfo.level = kGuildInfo._grade;
	ack.stInfo.member_count = pGuild->GetMemberTree().size();
	ack.stInfo.max_member_count = guildMaxUser; // resource data로 교체
	ack.stInfo.buff_type = kGuildInfo._buffType;
	ack.stInfo.buff_level = kGuildInfo._buffLevel;
	ack.stInfo.buff_value = kGuildInfo._buffValue;
	ack.stInfo.notice_flag = GetGuildExposureStatus(kGuildInfo._exposure, kGuildInfo._password);
	ack.stInfo.notice_text = kGuildInfo._intro;
	ack.stInfo.password = kGuildInfo._password;
	ack.stInfo.point = kGuildInfo._score;
	ack.stInfo.max_point = guildNextPoint;
	ack.stInfo.prev_point = kGuildInfo._prevScore; // snap shot 이 주기적으로 저장되어야 한다.
	ack.stInfo.rank = pGuild->GetRank();
	ack.stInfo.prev_rank = kGuildInfo._prevRank;

	//LOG(DEV, __FUNCTION__, "> name(", ack.stInfo.name.c_str(), ") master(", std::to_string(ack.stInfo.master_socialid).c_str(), ", ", ack.stInfo.master_nickname.c_str(), " )", " guild_seq: ", syn.guild_seq );

	pChannel->SendMsg(ack);
}


void
Msg::OnGuildMemberSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildInfoSyn syn;
	pPacket->Read(syn);

	GuildMemberAck kMembersAck;
	kMembersAck.user_seq = syn.user_seq;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")", " guild_seq: ", syn.guild_seq );

	//--------------------------------------------------------------------------------------------
	// 10. guild instance 존재 여부 파악
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( syn.guild_seq );
	if ( NULL == pGuild )
	{ // 길드 data를 DB에서 로딩
		pGuild = Static::Instance().LoadGuild( syn.guild_seq );
	}

	if ( NULL == pGuild )
	{
		pChannel->SendFail(kMembersAck, ACK_UNKNOWN_ERROR);
		return;
	}

	GuildServer::Guild::GuildInfo kGuildInfo = pGuild->GetData();
	std::shared_ptr<Member> pMaster = pGuild->GetMember( kGuildInfo._masterSeq );
	if ( NULL == pMaster )
	{
		pChannel->SendFail(kMembersAck, ACK_UNKNOWN_ERROR);
		return;
	}



	kMembersAck.result = ACK_OK;
	GuildServer::Guild::MEMBERTREE kMemberTree = pGuild->GetMemberTree();
	auto itrMember = kMemberTree.begin();
	for( ; itrMember != kMemberTree.end(); ++itrMember )
	{
		std::shared_ptr<Member> pMember = itrMember->second;
		if ( NULL == pMember ) continue;

		GuildMemberInfo kMemberInfo;
		kMemberInfo.seq = pMember->GetSeq();
		kMemberInfo.socialid = pMember->GetData()._socialID;
		kMemberInfo.nickname = pMember->GetData()._nickname;
		kMemberInfo.profile_url = pMember->GetData()._profileURL;
		kMemberInfo.level = pMember->GetData()._level;
		if ( kMemberInfo.seq == kGuildInfo._masterSeq )
			kMemberInfo.guild_grade = 1;
		else
			kMemberInfo.guild_grade = 10;
//		kMemberInfo.point = pMember->GetData()._contributeScore;
		kMemberInfo.point = pMember->GetData()._dailyScore;
		kMemberInfo.server_id = pMember->GetServer();
		kMemberInfo.logout_period = 1;
		kMemberInfo.requestToLogin = 1;

		kMembersAck.array_members.push_back( kMemberInfo );
	}

	pChannel->SendMsg(kMembersAck);
}


void
Msg::OnCreateGuildSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	CreateGuildSyn syn;
	pPacket->Read(syn);

	CreateGuildAck ack;
	ack.user_seq = syn.user_seq;
	ack.guild_seq = 0;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	NResource::ResourceGuildBanalce * pGuildBalance = NResource::Static::Instance().GetGuildBalance();

	if (NULL == pGuildBalance)
	{
		LOG(ERR, __FUNCTION__, " : pGuildBalance is NULL");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}


	// 길드 생성 비용 확인.
	int createGold = 0;
	{
		NResource::ResourceGuildBanalce::Flyweight * pFly = pGuildBalance->GetFly(GUILD_CREATE_NEED_GOLD);

		if (NULL == pFly)
		{
			LOG(ERR, __FUNCTION__, " : pFly(GUILD_CREATE_NEED_GOLD) is NULL");
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		if (syn.gold < static_cast<uint32_t>(pFly->_VALUE))
		{
			pChannel->SendFail(ack, ACK_GUILD_CREATE_NOT_ENOUGH_GOLD);
			return;
		}

		createGold = pFly->_VALUE;
	}

	// 길드 생성 권한 확인
	{
		NResource::ResourceGuildBanalce::Flyweight * pFly = pGuildBalance->GetFly(GUILD_CREATE_NEED_LEVEL);

		if (NULL == pFly)
		{
			LOG(ERR, __FUNCTION__, " : pFly(GUILD_CREATE_NEED_LEVEL) is NULL");
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		if (syn.level < pFly->_VALUE)
		{
			pChannel->SendFail(ack, ACK_GUILD_CREATE_REQUIRED_LEVEL);
			return;
		}
	}


	// 길드명 길이 최소 검사
	{
		if ( 2 > syn.guild_name.size() )
		{
			pChannel->SendFail(ack, ACK_GUILD_CREATE_FAILED);
			return;
		}
	}

	if ( 0 > syn.exposure || 1 < syn.exposure )
		syn.exposure = 1;



	//LOG(DEV, __FUNCTION__, "> 10. MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	// 길드 데이터 INSERT
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER), "call sp_insert_create_guild(", syn.user_seq, ", '"
			, syn.guild_name.c_str(), "', '", syn.password.c_str(), "', '", syn.notice_text.c_str(), "', '"
			, std::to_string(syn.socialid).c_str(), "', '", syn.nickname.c_str(), "', '", syn.profile_url.c_str(), "',", syn.level, ",", syn.exposure, ")");

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " : Fail call sp_create_guild");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	int idx = 1;
	uint32_t guild_seq = 0;
	int32_t result = 0;

	for (Database::ResultSet::iterator iter = res.begin(); iter != res.end(); iter++)
	{
		result = iter->getInt(idx++); // result
		guild_seq = iter->getInt(idx++);
		//guildSeq = iter->getInt("guild_seq");
		//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), 11. eRes: ", eRes, ", guild_seq: ", guildSeq );
	}

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), 20. eRes: ", eRes, ", guild_seq: ", guildSeq );

	if( 0 == result )
	{
		//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), 30. eRes: ", result, ", guild_seq: ", guildSeq );
		//time_t curTime = time(NULL);

		std::shared_ptr<Guild> pGuild = Static::Instance().NewGuild();
		pGuild->Initialize(pChannel->GetChannelKey(), guild_seq);

		Guild::GuildInfo clsGuildInfo;
		clsGuildInfo._masterSeq	= syn.user_seq;
		clsGuildInfo._name		= syn.guild_name;
		clsGuildInfo._intro		= syn.notice_text;
		clsGuildInfo._password	= syn.password;
		clsGuildInfo._exposure	= syn.exposure;
		clsGuildInfo._grade = 1;

		pGuild->Open(clsGuildInfo);

		std::shared_ptr<Member> pMember = Static::Instance().NewMember();
		pMember->Initialize(syn.user_seq);

		Member::MemberInfo clsMemberInfo;
		clsMemberInfo._guildSeq		= guild_seq;
		clsMemberInfo._level		= syn.level;
		clsMemberInfo._nickname		= syn.nickname;
		clsMemberInfo._profileURL	= syn.profile_url;
		clsMemberInfo._socialID		= syn.socialid;
		clsMemberInfo._loginTime	= time(NULL);
		clsMemberInfo._dailyInitTime = time(NULL);
		clsMemberInfo._dailyScore	= 0;
		clsMemberInfo._contributeScore = 0;
		clsMemberInfo._serverid		= syn.server_id;

		pMember->Open(clsMemberInfo);

		pGuild->AddMember(pMember);

		Static::Instance().AddGuild(pGuild);

		// 길드 점수 정보 Redis 반영 (길드 생성시 길드 점수는 0점)
		pGuild->ChangeScore(0);

		ack.result = ACK_OK;
		ack.guild_seq = guild_seq;
		ack.guild_grade = 1;
		ack.guild_name = syn.guild_name;
		ack.guild_create_gold = createGold;
	}
	else // 오류 경우
	{
		ack.result = result;
		ack.guild_seq = guild_seq;
	}


	//----------------------------------------------------------------------------
	// Added by spencer(2014.08.18
	// user_info table과 guild_member table 간의 데이터 불일치 건에 대한 보완
	// guild_member쪽의 data가 더 정확하다.(create/join the guild)
	//----------------------------------------------------------------------------
	if ( ACK_GUILD_CREATE_JOINED_ALREADY == result )
	{
		std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( guild_seq );
		if ( NULL == pGuild )
		{ // 길드 data를 DB에서 로딩
			pGuild = Static::Instance().LoadGuild( guild_seq );
		}

		if ( NULL != pGuild )
		{
			ack.result = ACK_OK;
			ack.guild_seq = guild_seq;
			ack.guild_grade = pGuild->GetData()._grade;
			ack.guild_name = pGuild->GetData()._name;
			ack.guild_create_gold = 0;

			LOG(DEV, __FUNCTION__, ">  ACK_GUILD_CREATE_JOINED_ALREADY> user_seq: ", syn.user_seq, ", guild_seq: ", guild_seq);
		}
//		RecoverGuildAck kRecoverGuildACK;
//		kRecoverGuildACK.user_seq = syn.user_seq;
//		int eRes = OnRecoverGuild( syn.user_seq, guildSeq, kRecoverGuildACK );
//		if ( ACK_OK == eRes )
//		{
//			pChannel->SendMsg( kRecoverGuildACK );
//			return;
//		}
//		else
//		{
//			ack.result = result;
//			ack.guild_seq = guildSeq;
//		}
	}

	pChannel->SendMsg(ack);
}

void
Msg::OnJoinGuildSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	JoinGuildSyn syn;
	pPacket->Read(syn);

	JoinGuildAck ack;
	ack.user_seq = syn.user_seq;
	ack.guild_seq = syn.guild_seq;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. user_seq : ", syn.user_seq, " guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 이미 길드원인 경우
	if (true == pGuild->IsExistMember(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " Already guild member. user_seq : ", syn.user_seq, " guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	if (0 < pGuild->GetData()._password.length())
	{
		if (0 != pGuild->GetData()._password.compare(syn.password))
		{
			LOG(ERR, __FUNCTION__, " invalid password. user_seq : ", syn.user_seq, " guild_seq : ", syn.guild_seq);
			pChannel->SendFail(ack, ACK_GUILD_JOIN_PASSWORD_MISMATCH);
			return;
		}
	}

	uint32_t tmCooldown = 0;
	int16_t result = pGuild->JoinMember(syn, tmCooldown); // 함수 내부에서 최대 인원 검사를 수행한다.




	if (result == ACK_OK && NULL != pGuild )
	{
		ack.guild_grade	= pGuild->GetData()._grade;
		ack.guild_name	= pGuild->GetData()._name;
		ack.buff_tid	= pGuild->GetData()._buffType;
		ack.buff_level	= pGuild->GetData()._buffLevel;
		ack.buff_value	= pGuild->GetData()._buffValue;
	}
	else if ( ACK_GUILD_JOIN_NOT_COOL_DOWN_YET == result )
	{
		ack.guild_seq = tmCooldown; //
	}
	else if ( ACK_GUILD_JOIN_JOINED_ALREADY == result )
	{
		//----------------------------------------------------------------------------
		// Added by spencer(2014.08.18
		// user_info table과 guild_member table 간의 데이터 불일치 건에 대한 보완
		// guild_member쪽의 data가 더 정확하다.(create/join the guild)
		//----------------------------------------------------------------------------
		uint32_t guild_seq = tmCooldown;
		pGuild = Static::Instance().GetGuild( guild_seq );
		if ( NULL == pGuild )
		{ // 길드 data를 DB에서 로딩
			pGuild = Static::Instance().LoadGuild( guild_seq );
		}

		if ( NULL != pGuild )
		{
			result = ACK_OK;
			ack.guild_seq = guild_seq;

			LOG(DEV, __FUNCTION__, ">  ACK_GUILD_JOIN_JOINED_ALREADY> user_seq: ", syn.user_seq, ", guild_seq: ", guild_seq);
		}
//		RecoverGuildAck kRecoverGuildACK;
//		kRecoverGuildACK.user_seq = syn.user_seq;
//		int eRes = OnRecoverGuild( syn.user_seq, tmCooldown, kRecoverGuildACK );
//		if ( ACK_OK == eRes )
//		{
//			pChannel->SendMsg( kRecoverGuildACK );
//			return;
//		}
//		else
//		{
//			ack.guild_seq = tmCooldown;
//		}
	}

	ack.result = result;

	pChannel->SendMsg(ack);
}

void
Msg::OnLeaveGuildSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	LeaveGuildSyn syn;
	pPacket->Read(syn);

	LeaveGuildAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 존재하지 않는 길드원
	if (false == pGuild->IsExistMember(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " not exists member. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	int16_t result = 0;

	// 길드 마스터인 경우 길드 해체
	if (true == pGuild->IsGuildMaster(syn.user_seq))
	{
		// 길드원이 남아 있는 경우 해체 불가
		if (0 < pGuild->GetMemberCountExceptMaster())
		{
			LOG(ERR, __FUNCTION__, " remain member in guild. user_seq : ", syn.user_seq);
			pChannel->SendFail(ack, ACK_GUILD_DISBAND_MEMBERS_ARE_EXISTED);
			return;
		}

		result = pGuild->LeaveMaster();
	}
	else
	{
		result = pGuild->LeaveMember(syn.user_seq);
	}

	ack.result	 = result;
	pChannel->SendMsg(ack);
}

void
Msg::OnKickoutGuildMemberSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	KickoutGuildMemberSyn syn;
	pPacket->Read(syn);

	KickoutGuildMemberAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 마스터가 아닌 경우 추방 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_GUILD_KICKOUT_GUILD_MASTER_DO_IT_ONLY);
		return;
	}

	// 존재하지 않는 길드원
	if (false == pGuild->IsExistMember(syn.member_seq))
	{
		LOG(ERR, __FUNCTION__, " not exists member. member_seq : ", syn.member_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	if (syn.user_seq == syn.member_seq)
	{
		LOG(ERR, __FUNCTION__, " invalid request. user_seq : ", syn.user_seq, " member_seq : ", syn.member_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	int16_t result = pGuild->KickoutMember(syn.member_seq);

	ack.result		= result;
	ack.guild_point	= pGuild->GetData()._score;

	pChannel->SendMsg(ack);
}

void
Msg::OnGuildBuffGachyaSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildBuffGachyaSyn syn;
	pPacket->Read(syn);

	GuildBuffGachyaAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 버프 뽑기는 길드 마스터가 아닌 경우 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 버프 종류 / 레벨 결정
	int buffType = 0;
	int buffLevel = 0;
	{
		NResource::ResourceGuildBuff * pBuff = NResource::Static::Instance().GetGuildBuff();
		if (NULL == pBuff)
		{
			LOG(ERR, __FUNCTION__, " pBuff is NULL.");
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		NResource::ResourceGuildBuff::Flyweight * pFly = pBuff->GetFly(pGuild->GetData()._grade);
		if (NULL == pFly)
		{
			LOG(ERR, __FUNCTION__, " pFly is NULL. guild_grade : ", pGuild->GetData()._grade);
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		buffType = pBuff->GetBuffType(pFly);
		buffLevel = pBuff->GetBuffLevel(pFly);
	}

	// 버프 수치 결정
	int buffValue = 0;
	{
		NResource::ResourceGuildBuffValue * pBuffValue = NResource::Static::Instance().GetGuildBuffValue();
		if (NULL == pBuffValue)
		{
			LOG(ERR, __FUNCTION__, " pBuffValue is NULL.");
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		NResource::ResourceGuildBuffValue::Key clsKey;
		clsKey.tid		= buffType;
		clsKey.level	= buffLevel;

		NResource::ResourceGuildBuffValue::Flyweight * pFly = pBuffValue->GetFly(clsKey);
		if (NULL == pFly)
		{
			LOG(ERR, __FUNCTION__, " pFly is NULL. buff_tid : ", buffType, " buff_leve : ", buffLevel);
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		buffValue = pFly->skill_value;
	}

	// 버프 정보 DB 갱신
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_update_guild_buff(",
					syn.guild_seq, ",",
					buffType, ",",
					buffLevel, ",",
					buffValue, ")"
			);

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_update_guild_buff.");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	auto iter = res.begin();

	int nRet = iter->getInt(1);

	if (0 != nRet)
	{
		LOG(ERR, __FUNCTION__, " Guild Buff update exception. nRet : ", nRet);
		pChannel->SendFail(ack, nRet);
		return;
	}

	pGuild->GetData()._buffType		= buffType;
	pGuild->GetData()._buffLevel	= buffLevel;
	pGuild->GetData()._buffValue	= buffValue;

	ack.result		= ACK_OK;
	ack.buff_tid	= buffType;
	ack.buff_level	= buffLevel;
	ack.buff_value	= buffValue;

	pChannel->SendMsg(ack);
}

void
Msg::OnUpdateGuildJoinPasswordSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	UpdateGuildJoinPasswordSyn syn;
	pPacket->Read(syn);

	UpdateGuildJoinPasswordAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 마스터가 아닌 경우 패스워드 변경 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 패스워드 DB 갱신
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_update_guild_join_password(",
					syn.guild_seq, ",",
					"'", syn.password.c_str(), "')"
			);

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_update_guild_join_password.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	auto iter = res.begin();

	int nRet = iter->getInt(1);

	if (0 != nRet)
	{
		LOG(ERR, __FUNCTION__, " Guild password update exception. nRet : ", nRet);
		pChannel->SendFail(ack, nRet);
		return;
	}

	pGuild->GetData()._password = syn.password;

	ack.result	= ACK_OK;
	pChannel->SendMsg(ack);
}

void
Msg::OnUpdateGuildNoticeSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	UpdateGuildNoticeSyn syn;
	pPacket->Read(syn);

	UpdateGuildNoticeAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 마스터가 아닌 경우 모집 Flag 변경 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	if ( 0 > syn.flag || 1 < syn.flag )
		syn.flag = 1;

	// 모집 Flag DB 갱신
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_update_guild_exposure(",
					syn.guild_seq, ",",
					syn.flag, ")"
			);

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_update_guild_exposure.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	auto iter = res.begin();

	int nRet = iter->getInt(1);

	if (0 != nRet)
	{
		LOG(ERR, __FUNCTION__, " Guild exposure update exception. nRet : ", nRet);
		pChannel->SendFail(ack, nRet);
		return;
	}

	pGuild->GetData()._exposure = syn.flag;

	ack.result	= ACK_OK;
	pChannel->SendMsg(ack);
}

void
Msg::OnUpdateGuildNoticeTextSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	UpdateGuildNoticeTextSyn syn;
	pPacket->Read(syn);

	UpdateGuildNoticeTextAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 마스터가 아닌 경우 소개글 변경 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 소개글 DB 갱신
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_update_guild_intro(",
					syn.guild_seq, ",",
					"'", syn.text, "')"
			);

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_update_guild_intro.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	auto iter = res.begin();

	int nRet = iter->getInt(1);

	if (0 != nRet)
	{
		LOG(ERR, __FUNCTION__, " Guild intro update exception. nRet : ", nRet);
		pChannel->SendFail(ack, nRet);
		return;
	}

	pGuild->GetData()._intro = syn.text;

	ack.result	= ACK_OK;
	pChannel->SendMsg(ack);
}


void
Msg::OnSearchGuildSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	SearchGuildSyn syn;
	pPacket->Read(syn);

	SearchGuildAck ack;
	ack.user_seq = syn.user_seq;
	ack.result = ACK_OK;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	// 길드 검색
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_select_search_guild('", syn.guild_name.c_str(), "')" );


	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_select_search_guild.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	if (0 == res.GetRowCount())
	{
		LOG(DEV, __FUNCTION__, "> Not found target guild.");
		pChannel->SendFail(ack, ACK_GUILD_SEARCH_NOT_FOUND_TARGET);
		return;
	}


	//auto iter = res.begin();

//	if (1 == res.GetRowCount())
//	{
//		uint32_t guild_seq = iter->getInt("guild_seq");
//		int iMemberCount = iter->getInt("mem_cnt");
//		if ( 0 == guild_seq && 0 == iMemberCount )
//		{
//			LOG(DEV, __FUNCTION__, "> Not found target guild.");
//			pChannel->SendFail(ack, ACK_GUILD_SEARCH_NOT_FOUND_TARGET);
//			return;
//		}
//	}



	//for( ; iter != res.end(); iter++ )
	for (Database::ResultSet::iterator iter = res.begin(); iter != res.end(); iter++)
	{
		GuildInfo kInfo;
		kInfo.seq = iter->getInt("guild_seq");
//		if ( 0 >= kInfo.seq )
//		{
//			LOG(DEV, __FUNCTION__, "> Not found target guild.");
//			pChannel->SendFail(ack, ACK_GUILD_SEARCH_NOT_FOUND_TARGET);
//			return;
//		}

		kInfo.name = iter->getString("guild_name").c_str();
		kInfo.password = iter->getString("guild_password").c_str();
		kInfo.level = iter->getInt("guild_grade");
		kInfo.master_seq = iter->getInt("guild_captain_seq");
		kInfo.master_nickname = iter->getString("guild_member_nickname").c_str();
		kInfo.master_level = iter->getInt("guild_member_level");
		int exposure = iter->getInt("guild_is_exposure");
		kInfo.notice_flag = GetGuildExposureStatus(exposure, kInfo.password);
		kInfo.notice_text = iter->getString("guild_intro").c_str();
		kInfo.prev_point = iter->getInt("guild_pre_score");
		kInfo.point = iter->getInt("guild_score");
		kInfo.member_count = iter->getInt("mem_cnt");


		::GuildServer::GuildRank& kRankList = ::GuildServer::Static::Instance().GetRankList();
		kInfo.rank = kRankList.GetRank( kInfo.seq );
		kInfo.prev_rank = kRankList.GetPrevRank( kInfo.seq );
		kInfo.prev_point = kRankList.GetPrevPoint( kInfo.seq );



		//LOG(DEV, __FUNCTION__, "> guild_seq: ", kInfo.seq, ", name: ", kInfo.name.c_str(), ", level: ", kInfo.level);


		// 길드 총원 산출
		NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
		if (NULL == pBalance)
		{
			LOG(ERR, __FUNCTION__, " pBalance is NULL");
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		int guildMaxUser =  pBalance->GetGuildMaxUser(kInfo.level);
		if (0 >= guildMaxUser)
		{
			LOG(ERR, __FUNCTION__, " Guild max user get fail. grade : ", kInfo.level);
			pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
			return;
		}

		kInfo.max_member_count = guildMaxUser;


		ack.array_Guilds.push_back( kInfo );
	}



	pChannel->SendMsg(ack);
}

void
Msg::OnUpdateGuildLevelSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	UpdateGuildLevelSyn syn;
	pPacket->Read(syn);

	UpdateGuildLevelAck ack;
	ack.user_seq = syn.user_seq;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") USER_SEQ(", syn.user_seq, "), GUILD_SEQ(", syn.guild_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	// 길드 마스터가 아닌 경우 변경 불가
	if (false == pGuild->IsGuildMaster(syn.user_seq))
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " pBalance is NULL");
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	int iLevel = pGuild->GetData()._grade;

	enum { eMaxLevel = 10, };

	if( eMaxLevel <= iLevel ) // TODO 추후에 이것도 상수(resource)로 변경을 해줘야 한다.
	{
		LOG(ERR, __FUNCTION__, " user is not master. user_seq : ", syn.user_seq);
		pChannel->SendFail(ack, ACK_GUILD_CHANGE_LEVEL_REACHED_MAX_LEVEL_ALREADY);
		return;
	}

	NResource::ResourceGuildBanalce::Flyweight * pFly = NULL;


	//LOG(DEV, __FUNCTION__, "> 10. level: ", iLevel, " , point: ", pGuild->GetData()._score);

	do
	{
		iLevel++;
		int iIndex = (iLevel - 1) * 3 + GUILD_1_GRADE_POINT;
		pFly = pBalance->GetFly((enum Balance)iIndex);
		if ( NULL == pFly )
			break;
		//LOG(DEV, __FUNCTION__, " index: ", iIndex, ", level: ", iLevel, " , point: ", pFly->_VALUE);
	}
	while ( NULL != pFly && pGuild->GetData()._score >= pFly->_VALUE && eMaxLevel > iLevel );

	if ( 1 < iLevel && eMaxLevel > iLevel )
		iLevel--;

	//LOG(DEV, __FUNCTION__, "> 20. level: ", iLevel, " , point: ", pGuild->GetData()._score);

	if ( iLevel == pGuild->GetData()._grade )
	{
		LOG(DEV, __FUNCTION__, "> guild_seq: ", syn.guild_seq, ", level: ", iLevel );
		pChannel->SendFail(ack, ACK_GUILD_CHANGE_LEVEL_NOT_ENOUGH_POINT);
		return;
	}

	// 모집 Flag DB 갱신
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_update_guild_grade(", syn.guild_seq, ",", iLevel, ")"	);

	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_update_guild_grade.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	auto iter = res.begin();

	int nRet = iter->getInt(1);

	if (0 != nRet)
	{
		LOG(ERR, __FUNCTION__, " call sp_update_guild_grade. nRet : ", nRet);
		pChannel->SendFail(ack, nRet);
		return;
	}

	pGuild->GetData()._grade = iLevel;

	ack.result	= ACK_OK;
	ack.level = iLevel;
	ack.point = pGuild->GetData()._score;
	ack.next_level_point = pFly->_VALUE;


	pChannel->SendMsg(ack);
}

void
Msg::OnGuildCoolDownSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	return;

	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildCoolDownSyn syn;
	pPacket->Read(syn);

	GuildCoolDownAck ack;
	ack.user_seq = syn.user_seq;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), guild_seq: ", syn.guild_seq );

	// 길드 검색
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER),
				"call sp_select_guild_member_status(", syn.user_seq, ", ", syn.guild_seq, ")" );


	if (0 != res.GetSQLError())
	{
		LOG(ERR, __FUNCTION__, " Fail call sp_select_guild_member_status.");
		pChannel->SendFail(ack, ACK_DB_ERROR);
		return;
	}

	auto iter = res.begin();
	if ( iter == res.end() )
	{
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	ack.result = ACK_OK;
	ack.guild_seq = iter->getInt("guild_seq");
	ack.status = iter->getInt("guild_member_status");
	ack.leave_time = iter->getInt("guild_brokentime");

	pChannel->SendMsg(ack);
}


void
Msg::OnGuildListSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildListSyn syn;
	pPacket->Read(syn);

	GuildListAck ack;
	ack.user_seq = syn.user_seq;
	ack.type = syn.type;
	ack.result = ACK_OK;

	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), type: ", ack.type, ", page: ", syn.page );


	// 추천 리스트
	if ( (int16_t)0 == ack.type )
	{
		GuildServer::Static::GUILDMAP krgGuild = Static::Instance().GetGuildMap();

		//LOG(DEV, __FUNCTION__, "> Recommended list> " );

		int iSize = krgGuild.size();
		iSize -= 20; // 한번에 20개씩 전달한다.

		auto iter = krgGuild.begin();

		int iIndex = 0;
		if ( 0 < iSize )
		{
			iIndex = rand() % iSize;
			for( int i = 0; i < iIndex; ++i )
				iter++;
		}

		//LOG(DEV, __FUNCTION__, "> Recommended list> iSize: ", iSize, ", index: ", iIndex );

		//::GuildServer::GuildRank& kRankList = ::GuildServer::Static::Instance().GetRankList();

		int iCount = 0;
		for( ; iter != krgGuild.end(); iter++ )
		{
			std::shared_ptr<Guild> pGuild = iter->second;

			if ( NULL == pGuild || 0 == pGuild->GetData()._exposure ) // 비노출은 제외
				continue;

			GuildInfo kInfo;
			kInfo.seq = pGuild->GetSeq();
			kInfo.name = pGuild->GetData()._name.c_str();
			kInfo.master_nickname = pGuild->GetMaster()->GetData()._nickname.c_str();
			kInfo.master_level = pGuild->GetMaster()->GetData()._level;
			kInfo.notice_flag = GetGuildExposureStatus(pGuild->GetData()._exposure, pGuild->GetData()._password);
			kInfo.point = pGuild->GetData()._score;
			kInfo.prev_point = pGuild->GetData()._score;
			kInfo.level = pGuild->GetData()._grade;
			kInfo.notice_text = pGuild->GetData()._intro.c_str();
			kInfo.max_member_count = pGuild->GetMaxMemberCount();
			kInfo.member_count = pGuild->GetMemberCount();
			kInfo.rank = pGuild->GetRank();
			kInfo.prev_rank = pGuild->GetData()._prevRank;

			//LOG(DEV, "GUILD> ", iCount, ". seq: ", kInfo.seq, ", name: ", kInfo.name.c_str(), ", count: ", kInfo.member_count, "/", kInfo.max_member_count, ", notice: ", kInfo.notice_text.c_str(), "(", kInfo.notice_flag, "), level: ", kInfo.level );

			ack.array_Guilds.push_back( kInfo );

			++iCount;
			if ( 20 <= iCount )
				break;
		}
	}
	else
	{ // TODO 랭킹 리스트
		::GuildServer::GuildRank& kRankList = ::GuildServer::Static::Instance().GetRankList();
		ack = kRankList.GetList( syn.page ); //
		ack.user_seq = syn.user_seq;

		//LOG(DEV, "RankList> page: ", syn.page, ", count: ", ack.array_Guilds.size() );
	}

	pChannel->SendMsg(ack);
}


void
Msg::OnApplyGuildPointSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ApplyGuildPointSyn syn;
	pPacket->Read(syn);

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		return;
	}

	std::shared_ptr<Member>	pMember = pGuild->GetMember(syn.user_seq);
	if (NULL == pMember)
	{
		LOG(ERR, __FUNCTION__, " pMember is NULL. user_seq : ", syn.user_seq);
		return;
	}

	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " pBalance is NULL");
		return;
	}

	NResource::ResourceGuildBanalce::Flyweight * pFly = NULL;

	if (1 == syn.contents)
	{
		switch (syn.value)
		{
		case 0 : pFly = pBalance->GetFly(GUILD_DUNGEON_NORMAL_CLEAR_POINT); break;
		case 1 : pFly = pBalance->GetFly(GUILD_DUNGEON_HARD_CLEAR_POINT); break;
		case 2 : pFly = pBalance->GetFly(GUILD_DUNGEON_HELL_CLEAR_POINT); break;
		}
	}
	else if (2 == syn.contents)
	{
		switch (syn.value)
		{
		case 0 : pFly = pBalance->GetFly(GUILD_PVP_LOSE_POINT); break;
		case 1 : pFly = pBalance->GetFly(GUILD_PVP_WIN_POINT); break;
		}
	}
	else if (3 == syn.contents)
	{
		switch (syn.value)
		{
		case 1 : pFly = pBalance->GetFly(GUILD_PK_WIN_POINT); break;
		default : pFly = pBalance->GetFly(GUILD_PK_LOSE_POINT); break;
		}
	}

	if (NULL == pFly)
	{
		LOG(ERR, __FUNCTION__, " pFly is NULL. contents : ", syn.contents, " value : ", syn.value);
		return;
	}

	int dailyMaxScore = pBalance->GetMemberDailyMaxScore();
	if (0 >= dailyMaxScore)
	{
		LOG(ERR, __FUNCTION__, " : member daily max score get fail.");
		return;
	}

	// 멤버 포인트 반영
	pMember->ChangeMemberScore(pFly->_VALUE, dailyMaxScore);
	pMember->SetMemberFlushDB(true);

	// 일일 최대 포인트를 획득한 경우 길드 포인트에 반영 하지 않는다.
	if (dailyMaxScore <= pMember->GetData()._dailyScore)
		return;

	// 길드 포인트 반영
	pGuild->ChangeScore(pFly->_VALUE);
	pGuild->SetFlushDB(true);
	pGuild->SetTimer();

	pGuild->UpdateGradeDown();
}


void
Msg::OnSendGuildMailCheckSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	SendGuildMailCheckSyn syn;
	pPacket->Read(syn);

	SendGuildMailCheckAck ack;
	ack.user_seq = syn.user_seq;

	LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, ")");

	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	if (false == pGuild->IsExistMember(syn.recv_user_seq))
	{
		LOG(ERR, __FUNCTION__, " Not exists member. user_seq : ", syn.recv_user_seq, " guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	ack.result			= ACK_OK;
	ack.recv_user_seq	= syn.recv_user_seq;
	ack.item_seq		= syn.item_seq;
	ack.bag_type		= syn.bag_type;
	ack.gold			= syn.gold;
	ack.tax				= syn.tax;
	ack.msg				= syn.msg;

	pChannel->SendMsg(ack);
}


void
Msg::OnGuildChatSyn(Dispatcher::Session * pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pChannel = (ChannelServer *)pSession;

	GuildChatSyn syn;
	pPacket->Read(syn);

	BroadcastGuildChatAck ack;
	ack.user_seq = syn.user_seq;
	ack.result = ACK_OK;
	ack.chat = syn.chat.c_str();


	//LOG(DEV, __FUNCTION__, " : MSG_ID(", syn.MSG_ID, ") SEQ(", syn.user_seq, "), guild: ", syn.guild_seq, ", chat: ", syn.chat.c_str());


	std::shared_ptr<Guild>	pGuild = Static::Instance().GetGuild(syn.guild_seq);
	if (NULL == pGuild)
	{
		LOG(ERR, __FUNCTION__, " pGuild is NULL. user_seq : ", syn.user_seq, " guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	std::shared_ptr<Member> pMember = pGuild->GetMember( syn.user_seq );
	if ( NULL == pMember )
	{
		LOG(ERR, __FUNCTION__, " pMember is NULL. user_seq : ", syn.user_seq, " guild_seq : ", syn.guild_seq);
		pChannel->SendFail(ack, ACK_UNKNOWN_ERROR);
		return;
	}

	ack.nickname = pMember->GetData()._nickname.c_str();

	GuildServer::Guild::MEMBERTREE mapMember = pGuild->GetMemberTree();
//	std::for_each(mapMember().begin(), mapMember().end(), [&](GuildServer::Guild::MEMBERTREE::value_type & pair){
//
//		if ( 0 >= pair.second->GetServer() ) // offline
//			continue;
//
//		ack.array_Members.push_back( pair.first );
//	});

	auto iter = mapMember.begin();
	for( ; iter != mapMember.end(); ++iter )
	{
		if ( 0 >= iter->second->GetServer() )
			continue;
		ack.array_Members.push_back( iter->first );
	}

	// 모든 채널 서버에 메시지를 보내줘야 한다.
	//::GuildServer::Static::Instance().BroadcastChatMsgToChannelServerAll(ack);
	::GuildServer::Static::Instance().BroadcastMsgToChannelServerAll(ack);

	//pChannel->SendMsg(ack);
}

int
Msg::OnRecoverGuild( uint32_t a_user_seq, uint32_t a_guild_seq, RecoverGuildAck& ack )
{
	//--------------------------------------------------------------------------------------------
	// 10. guild instance 존재 여부 파악
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Guild> pGuild = Static::Instance().GetGuild( a_guild_seq );
	if ( NULL == pGuild )
	{ // 길드 data를 DB에서 로딩
		pGuild = Static::Instance().LoadGuild( a_guild_seq );
	}

	if ( NULL == pGuild ) // 길드 정보 loading에 실패할 수 있다.
	{
		return ACK_DB_ERROR;
	}


	GuildServer::Guild::GuildInfo kGuildInfo = pGuild->GetData();

	//--------------------------------------------------------------------------------------------
	// 20. 내가 길드에 가입되어 있는지 확인
	//--------------------------------------------------------------------------------------------
	std::shared_ptr<Member> pMember = pGuild->GetMember( a_user_seq );
	if ( NULL == pMember )
	{ // 내가 가입되어 있지 않다. 즉 내가 추방되었다. front-end에 이를 전달해서 최종적으로 client에 해당 메시지를 출력한다. "길드에서 추방되었습니다."
		return ACK_UNKNOWN_ERROR;
	}


	std::shared_ptr<Member> pMaster = pGuild->GetMember( kGuildInfo._masterSeq );
	if ( NULL == pMaster )
	{
		LOG(ERR, __FUNCTION__, " Master is null.");
		return ACK_UNKNOWN_ERROR;
	}


	NResource::ResourceGuildBanalce * pBalance = NResource::Static::Instance().GetGuildBalance();
	if (NULL == pBalance)
	{
		LOG(ERR, __FUNCTION__, " pBalance is NULL.");
		return ACK_UNKNOWN_ERROR;
	}

	int guildMaxUser =  pBalance->GetGuildMaxUser(kGuildInfo._grade);
	if (0 >= guildMaxUser)
	{
		LOG(ERR, __FUNCTION__, " Guild max user get fail. grade : ", kGuildInfo._grade);
		return ACK_UNKNOWN_ERROR;
	}

	int guildNextPoint = pBalance->GetNextGradeGuildScore(kGuildInfo._grade);
	if (0 >= guildNextPoint)
	{
		LOG(ERR, __FUNCTION__, " Guild next point get fail.");
		return ACK_UNKNOWN_ERROR;
	}


	LOG(DEV, __FUNCTION__, "> ", a_user_seq, " guild_seq : ", a_guild_seq );

	ack.result = ACK_OK;
	ack.stInfo.seq = pGuild->GetSeq();
	ack.stInfo.name = kGuildInfo._name;
	ack.stInfo.master_seq = kGuildInfo._masterSeq;
	ack.stInfo.master_socialid = pMaster->GetData()._socialID;
	ack.stInfo.master_nickname = pMaster->GetData()._nickname;
	ack.stInfo.master_profile_url = pMaster->GetData()._profileURL;
	ack.stInfo.master_level = pMaster->GetData()._level;
	ack.stInfo.level = kGuildInfo._grade;
	ack.stInfo.member_count = pGuild->GetMemberTree().size();
	ack.stInfo.max_member_count = guildMaxUser;
	ack.stInfo.buff_type = kGuildInfo._buffType;
	ack.stInfo.buff_level = kGuildInfo._buffLevel;
	ack.stInfo.buff_value = kGuildInfo._buffValue;
	ack.stInfo.notice_flag = GetGuildExposureStatus(kGuildInfo._exposure, kGuildInfo._password);
	ack.stInfo.notice_text = kGuildInfo._intro;
	ack.stInfo.password = kGuildInfo._password;
	ack.stInfo.point = kGuildInfo._score;
	ack.stInfo.max_point = guildNextPoint; // resource data로 교체
	ack.stInfo.prev_point = kGuildInfo._prevScore; // snap shot 이 주기적으로 저장되어야 한다.
	ack.stInfo.rank = pGuild->GetRank();
	ack.stInfo.prev_rank = kGuildInfo._prevRank;

	return ACK_OK;
}

} /*GuildServer*/
